﻿//#define ENABLE_PROFILER
using UnityEngine;
using System.Collections;
using TTGame;
using System.Collections.Generic;
using System;

/*
 * Puppet
 * 挂载在人物Prefab上的基础脚本
 *
 * 人物对象类。
 * 拥有人物所有对外接口和子功能类引用。
 * 管理人物的所有逻辑，当然，尽量将逻辑分为子功能脚本，如FSM，仇恨列表，AI，技能，Buff管理。
 * 子功能脚本应做成插件式，可增可减，减少耦合。
 *
 * 依赖：
 * FSM等子功能类。其他子功能脚本类都是插件式，可增可减。
 *
 * ！不写重复代码！
 * @author TTun
 * @date 7/12/2017 5:16:56 PM
 */
namespace TTGameEngine {
public enum PuppetTypeID {
    Monster = 1,
    Soldier,
    Building,
    Player,
    AltarSoldier,
}

public enum PuppetStateID {
    Stand,
    Show,
    Run,
    Hurt,
    ClimbUp,
    Reload,
    Death,
    Skill,
    Win,
    Control, //人物被控制了。就是单纯的播动画，类似受伤状态。
    Count,
}

public enum PuppetPointType {
    None = 0,
    SelfTransform = 1,
    HitPoint,
    BuffPoint,
    Point,
    AttackPoint,
    ShotPoint,
    LockPoint,
}

[SerializeField]
public class ControlInfo {
    public string m_controlAnim;
    public ControlState m_controlState;
    [Tooltip("time=0：与动画事件一致")]
    public float m_controlTime = 0;
    //[Tooltip("动画通过加减速与持续时间同步")]
    //public bool m_isSynAnim = false;
}

public class Puppet : MonoBehaviour {

    static public bool PuppetLogFlag = true;

//++++++++++运行时变量++++++++++
//----------人物属性相关----------
    public Transform objTF;
    public bool m_invisible = true;
    [SerializeField, ReadOnly, Tooltip("nameEn_服务器ID_位置#随机数")]
    string objGID = "";         //本地的唯一ID
    public string nameEn;
    public int serverObjDataID; //服务器下发的玩家ID
    public string nameCn;
    public ObjType m_objType = ObjType.PlayerSelf;
    [SerializeField, ReadOnly]
    ObjType m_realObjTypeID = ObjType.None;
    //对象隐藏/显示时控制的节点。
    [SerializeField, ReadOnly]
    Renderer[] m_visibleNodes;
    Collider[] m_colliders;
    [SerializeField, ReadOnly]
    CapsuleCollider m_puppetCollider;
    //从CapsuleCollider脚本中读取的
    float m_objheight = 5f;
    [SerializeField, ReadOnly, Tooltip("从CapsuleCollider脚本中读取的")]
    float m_colliderRange = 1f;
    Transform headPosTF;
    bool m_isTimeFreezing = false;
    float t_bulletEffectCD;
    //buff中填的propID，float属性从50开始。
    public static readonly int BUFF_FLOAT_PROP_BEGIN = 50;

//----------调整参数----------
    [Tooltip("子弹与人物碰撞框碰撞点的半径调整")]
    public float HitPosFactor = 0.87f;
    public float HitPosHeight = 2f;
//----------移动相关----------
    [SerializeField]
    MoveInfo m_moveInfo = new MoveInfo(); //人物常规移动的信息。
    /// <summary>
    /// 技能位移，不受摇杆、AI移动影响。由技能中设置。
    /// 技能状态中，主要处理技能位移，不处理普通位移
    /// </summary>
    MoveInfo m_skillMoveInfo = null;
    [SerializeField]
    Dictionary<string, MoveInfo> m_forceMoveInfos = new Dictionary<string, MoveInfo>();
    Vector3 m_targetLookingDir;
    Quaternion m_targetLookingDirQ;
    [SerializeField, Tooltip("角度")]
    float m_lookingRotationSpeed = 720f;
    public float LookingRotationSpeed { get { return m_lookingRotationSpeed; } }
    [Tooltip("移动碰撞排斥范围")]
    public float moveColliderRange = 1f;

//----------战斗相关----------
    public float t_curGCD = 0.1f;
    [Tooltip("大招释放后的共CD")]
    public float ActiveSkillPostCD = 1f;
    //用于显示子弹数、装载子弹
    SkillTL curGunSkill;
    [SerializeField]
    bool IsInfinitiBullet = true; //无限子弹
    [HideInInspector]
    public DamageInfo curDamageInfo;
    [SerializeField]
    float MaxGuardTime = 5f;
    float m_onGuardTime = 0;
    float m_fetterAtkRate = 1f;
    //所在位置的ID。
    public int SeatID = 0;
    //数据表所在idx。进入战斗时，人物根据战斗优先级重新排序过。在重新排序过之后，如果需要索引人物数据应该使用DataIdx，而不是人物数组id。
    public int DataIdx = 0;
    public int HeadIconIdx = 0;
    Dictionary<int, AmmoPouch> bulletPackage = new Dictionary<int, AmmoPouch>();
    Dictionary<string, Transform> m_posTFCache = new Dictionary<string, Transform>();

    #region 测试开关
    //状态提前结束，为了给下一个状态动画过渡留出时间。
    [HideInInspector]
    static public float StateEndingTimeFactor = 1f;
    //本意是防止状态过快的切换。由于会导致状态切换受限，暂时去除。
    [HideInInspector]
    public float StateLimitTimeFactor = 0f;
    #endregion

    #region 动画相关
    public string standAnimName;
    public string attackStandAnimName;
    public string showAnimName;
    public string runAnimName;
    public string lightHurtForwardAnimName;
    public string lightHurtBackwardAnimName;
    public string heavyHurtForwardAnimName;
    public string heavyHurtBackwardAnimName;
    public string knowDownForwardAnimName;
    public string knowDownBackwardAnimName;
    public string climbUpForwardAnimName;
    public string climbUpBackwardAnimName;
    public string winAnimName;
    public string deadAnimName;
    public string reloadAnimName;
    [Tooltip("填0，以动画时间为准")]
    public float reloadTime;
    //融合动画
    public string mixLightHurtFAnimName;
    public Transform MixBoneTF_lightHurt;
    bool isMixBone = false;
    [Tooltip("死亡后的残骸预制体")]
    public string deadRemainsPrefab;
    #endregion
    #region FPS技能参数，如果该英雄有FPS技能的话
    //[Tooltip("FPS攻击时间间隔")]
    //public float fpsAtkCD;
    //[Tooltip("FPS模式持续时间")]
    //public float fpsTime;
    //public string fpsBulletTag;
    public string fpsManPrefab;
    public Vector3 fpsModelOffset;
    public string fpsMuzzleEffectPrefab;
    [Tooltip("FPS模型的站立动画")]
    public string fpsAttackStandAnimName;
    [Tooltip("FPS模型的攻击动画")]
    public string fpsAttackAnimName;
    [Tooltip("FPS点击一次后动画和特效最短持续时间")]
    public float fpsMaxAttackShowTime;
    #endregion
    #region 声音相关
    public float footAnimPoint1;
    public float footAnimPoint2;
    public string[] deathSoundNames;
    public string[] heavyDamageSoundNames;
    public string[] lightDamageSoundNames;
    public string[] pushbackDamageSoundNames;
    public string[] footstepSoundNames;
    [Tooltip("动画百分比")]
    public float reloadSoundPlayTime = 0.5f;
    public string reloadSoundName;

    #endregion

    #region 子功能模块
    [HideInInspector]
    public PuppetProperty m_prop;
    FSMSystem m_FSMSystem;
    public AnimPlayer m_animPlayer;
    [SerializeField]
    Animation m_animation;
    PuppetSkillCircle m_skillCircle;
    SkillPackage m_skillPackage;
    public SkillTimelineSystem m_skillsystem;
    public PuppetAI m_puppetAI;
    BuffContainer m_buffContainer;
    public CharacterController controller;
    #endregion

    #region 事件回调
    public delegate void PuppetEvent(Puppet obj);
    public delegate void OnIntPropChange(Puppet obj, int aOldValue, int aNewValue);

    PuppetEvent onDeadRelease;
    OnIntPropChange onPropChangeHP;
    OnIntPropChange onPropChangeAnger;
    #endregion


    Transform m_posRootTF = null;
    public Transform PosRootTF {
        get { return m_posRootTF; }
    }

    public void RegistOnHPChange(OnIntPropChange cb) {
        onPropChangeHP -= cb;
        onPropChangeHP += cb;
    }

    public void RegistOnAngerChange(OnIntPropChange cb) {
        onPropChangeAnger -= cb;
        onPropChangeAnger += cb;
    }

    //其他绑定在人物身上的对象，默认位置
    Transform m_bindObjsRootTF = null;
    public Transform BindObjsRootTF {
        get { return m_bindObjsRootTF; }
    }

    [SerializeField]
    float m_fadeToNextAnimTime = 0.2f;
    public float FadeToNextAnimTime {
        get { return m_fadeToNextAnimTime; }
    }

    public Animation Anim {
        get { return m_animation; }
    }

    public float FetterAtkRate {
        get { return m_fetterAtkRate; }
    }
    public Vector3 CurMoveDir {
        get { return PuppetMoveInfo.lastMoveDir; }
        //set { m_curMoveDirection = value; }
    }

    //目标面向。注意，不是人物当前的面向
    public Vector3 TargetLookingDir {
        get { return m_targetLookingDir; }
    }
    public Quaternion TargetLookingDirQ {
        get { return m_targetLookingDirQ; }
    }

    public Vector3 CurLookingDir {
        get { return objTF.forward; }
    }

    private SkillAnimInfo m_skillInfo = null;
    private SkillAnimInfo m_nextSkillInfo = null;
    public SkillAnimInfo SkillInfo {
        get { return m_skillInfo; }
        set { m_skillInfo = value; }
    }
    public SkillAnimInfo NextSkillInfo {
        get { return m_nextSkillInfo; }
        set { m_nextSkillInfo = value; }
    }

    public SkillPackage SkillPackage {
        get { return m_skillPackage; }
    }

    public Vector3 MoveTargetPos {
        get { return m_moveInfo.moveTargetPos; }
    }

    public MoveInfo PuppetMoveInfo {
        get { return m_moveInfo; }
    }

    public MoveInfo PuppetSkillMoveInfo {
        get { return m_skillMoveInfo; }
    }

    public Dictionary<string, MoveInfo> PuppetForceMoveInfos {
        get { return m_forceMoveInfos; }
    }

    public Vector3 Pos {
        get {return objTF.position;}
    }

    public float BulletEffectCD {
        get { return t_bulletEffectCD; }
        set { t_bulletEffectCD = value; }
    }

    public float MoveSpeed {
        get {
            return GetPropWithBuff(PuppetIntPropID.Prop_move);
        }
    }
    public PuppetStateID StateID {
        get {
            if(m_FSMSystem != null)
                return (PuppetStateID)(m_FSMSystem.CurrentState);
            else
                return PuppetStateID.Stand;
        }
    }
    public Puppet Locker {
        get {
            if(m_puppetAI) {
                return m_puppetAI.locker;
            }
            return null;
        }
    }

    //人物攻击力
    public int AttackPoint {
        get {
            float dmg = GetPropWithBuff(PuppetIntPropID.Prop_att);
            dmg = m_buffContainer.ApplyAttackDamage(dmg);
            return (int)dmg;
        }
    }

    public int DefensePoint {
        get { return (int)GetPropWithBuff(PuppetIntPropID.Prop_def); }
    }
    public int CurAnger {
        get { return (int)GetPropWithBuff(PuppetIntPropID.Prop_curAnger); }
        set {
            int newAnger = value;
            int oldValue = m_prop.GetIntProp(PuppetIntPropID.Prop_curAnger);
            if(DebugSetting.Self != null && DebugSetting.Self.HeroFullAnger) {
                newAnger = MaxAnger;
            }
            if(value != oldValue) {
                int newValue = Mathf.Clamp(newAnger, 0, m_prop.GetIntProp(PuppetIntPropID.Prop_angerMax));
                m_prop.SetIntProp(PuppetIntPropID.Prop_curAnger, newValue);
                if(onPropChangeAnger != null) {
                    onPropChangeAnger(this, oldValue, newValue);
                }
            }
        }
    }
    public int MaxAnger {
        get {
            return (int)GetPropWithBuff(PuppetIntPropID.Prop_angerMax); ;
        }
    }
    virtual public int CurHp {
        get { return (int)GetPropWithBuff(PuppetIntPropID.Prop_curHp); }
        set {
            int oldPropHP = m_prop.GetIntProp(PuppetIntPropID.Prop_curHp);
            if(value != oldPropHP) {
                int newValue = Mathf.Clamp(value, 0, m_prop.GetIntProp(PuppetIntPropID.Prop_hp));
                m_prop.SetIntProp(PuppetIntPropID.Prop_curHp, newValue);
                if(onPropChangeHP != null) {
                    onPropChangeHP(this, oldPropHP, newValue);
                }
            }
            if(value <= 0) {
                m_isDead = true;
            }
        }
    }

    public int Lv {
        get { return GetRawProp(PuppetIntPropID.Prop_lv); }
    }

    public int PrefabID {
        get { return GetRawProp(PuppetIntPropID.Prop_hero_id); }
    }

    bool m_isActived = false;
    //是否已激活。两边队伍站好队开打之前，都是未激活。
    //未激活的话，不会受到伤害。
    public bool IsActived {
        get { return m_isActived; }
    }

    public void CallOnPropChange(PuppetIntPropID intPropID, int oldValue, int newValue) {
        switch(intPropID) {
            case PuppetIntPropID.Prop_curHp:
                if(onPropChangeHP != null) {
                    onPropChangeHP(this, oldValue, newValue);
                }
                break;
            case PuppetIntPropID.Prop_curAnger:
                if(onPropChangeAnger != null) {
                    onPropChangeAnger(this, oldValue, newValue);
                }
                break;
        }
    }
    public void CallOnPropChange(PuppetFloatPropID floatPropID, float oldValue, float newValue) {
        switch(floatPropID) {
            case PuppetFloatPropID.Prop_atkRate:
                break;
        }
    }

    //返回0~1
    public float CurHpPrecent {
        get { return (float)CurHp / MaxHp; }
    }

    bool m_isDead = false;
    virtual public bool IsDead {
        get {
            if(CurHp > 0 && m_isDead) {
                DebugUtil.LogErrorFormat("[Puppet] Dead, but hp not zero. [{0}] hp:[{1}]", name, CurHp);
            }
            return m_isDead;
        }
    }

    public bool IsDeadAndRelase {
        get { return m_isDead && m_invisible == false; }
    }

    public int MaxHp {
        get {
            return (int)GetPropWithBuff(PuppetIntPropID.Prop_hp); ;
        }
    }

    public float MaxGCD {
        get {
            return GetPropWithBuff(PuppetFloatPropID.Prop_atkRate); ;
        }
    }

    Transform m_damagePos;
    public Vector3 ShowDamagePos {
        get {
            if(m_damagePos != null) {
                return m_damagePos.position;
            } else {
                return objTF.position;
            }
        }
    }

    public float ObjHeight {
        get { return m_objheight; }
    }
    public Vector3 ObjHeadPos {
        get { return headPosTF.position; }
    }

    void Awake() {
        initObj();
        initTestData();

    }
    // Use this for initialization
    void Start() {


        //ObjectManager.Share().AddObject(this);

        //ResetObj();
        //ActiveObj();
    }

    #region 初始化
    void initTestData() {
        IsInfinitiBullet = true;
        bulletPackage.Add(0, new AmmoPouch(0, 99999, IsInfinitiBullet));
        bulletPackage.Add(1, new AmmoPouch(1, 99999, IsInfinitiBullet));
        bulletPackage.Add(2, new AmmoPouch(2, 99999, IsInfinitiBullet));
    }

    bool debug_isInitWithServerData = false;

    int _heroSeatPrior = 0;
    //优先级数字越小越优先。怪物没有位置优先级概念，以最大值计算。
    public int SeatPrior {
        get { return _heroSeatPrior; }
    }

//     public void InitWithHeroServerData(BattleServerData.EroicaSData heroSData, LTHeroConfigInfo heroConfig) {
//         m_isDead = false;
//         serverObjDataID = heroSData.heroID;
//         nameCn = heroConfig.name;
//         m_fetterAtkRate = BattleServerData.Share().FetterAtkRate;
//
//         for(int i = 0; i < heroSData.intProps.Count; i++) {
//             m_prop.SetIntProp((PuppetIntPropID)i, heroSData.intProps[i]);
//         }
//         for(int i = 0; i < heroSData.floatProps.Count; i++) {
//             m_prop.SetFloatProp((PuppetFloatPropID)i, heroSData.floatProps[i]);
//         }
//         m_prop.SetStrProp(PuppetStrPropID.HeadIcon, heroConfig.icon);
//         m_prop.SetIntProp(PuppetIntPropID.Prop_curHp, m_prop.GetIntProp(PuppetIntPropID.Prop_hp));
//         m_prop.SetStrProp(PuppetStrPropID.HeroType, heroConfig.GetHeroTypeIcon());
//         _heroSeatPrior = m_prop.GetIntProp(PuppetIntPropID.Prop_seatPrior);
//         if(m_prop.GetIntProp(PuppetIntPropID.Prop_hp) <= 0) {
//             m_prop.SetIntProp(PuppetIntPropID.Prop_hp, 1);
//         }
//         if(m_prop.GetIntProp(PuppetIntPropID.Prop_angerMax) <= 0) {
//             m_prop.SetIntProp(PuppetIntPropID.Prop_angerMax, 1);
//         }
//         //mark:notice Grade在战斗前存储。在战斗中应该不会变化吧。：）
//         //m_prop.SetIntProp(PuppetIntPropID.Prop_grade, LTHeroController.getInstance().getHeroGrade(serverObjDataID));
//
//         m_skillPackage.InitWithServerData();
//         debug_isInitWithServerData = true;
//         GetGID();
//     }

//     public void InitWithEnemyServerData(BattleServerData.MonsterObjSData monsterSData) {
//         m_isDead = false;
//         serverObjDataID = monsterSData.id;
//         m_prop.SetIntProp(PuppetIntPropID.Prop_id, monsterSData.id);
//         m_prop.SetIntProp(PuppetIntPropID.Prop_hero_id, monsterSData.id);
//         m_prop.SetIntProp(PuppetIntPropID.Prop_hp, monsterSData.hp);
//         m_prop.SetIntProp(PuppetIntPropID.Prop_att, monsterSData.att);
//         m_prop.SetIntProp(PuppetIntPropID.Prop_def, monsterSData.def);
//         m_prop.SetIntProp(PuppetIntPropID.Prop_move, monsterSData.move);
//
//         m_prop.SetFloatProp(PuppetFloatPropID.Prop_atkRate, monsterSData.rate);
//
//         nameCn = monsterSData.name;
//         m_prop.SetStrProp(PuppetStrPropID.HeadIcon, monsterSData.icon);
//         m_prop.SetIntProp(PuppetIntPropID.Prop_curHp, m_prop.GetIntProp(PuppetIntPropID.Prop_hp));
//         if(m_prop.GetIntProp(PuppetIntPropID.Prop_hp) <= 0) {
//             m_prop.SetIntProp(PuppetIntPropID.Prop_hp, 1);
//         }
//         if(m_prop.GetIntProp(PuppetIntPropID.Prop_angerMax) <= 0) {
//             m_prop.SetIntProp(PuppetIntPropID.Prop_angerMax, 1);
//         }
//         m_skillPackage.InitWithServerData();
//         _heroSeatPrior = int.MaxValue;
//
//         debug_isInitWithServerData = true;
//         GetGID();
//     }

    void initObj() {
        //Profiler.BeginSample("Puppet.Init1");
        Invisable = true;
        m_isDead = false;
        objTF = this.transform;
        if(m_FSMSystem == null) m_FSMSystem = gameObject.AddComponent<FSMSystem>();
        if(m_skillsystem == null) m_skillsystem = gameObject.AddComponent<SkillTimelineSystem>();
        if(m_buffContainer == null) m_buffContainer = gameObject.AddComponent<BuffContainer>();

        effects.Clear();
        pausedEffects.Clear();

        m_skillsystem.RegistCB_SkillsCastBegin(OnSkillCastBegin);
        m_skillsystem.RegistCB_SkillsFinished(OnSkillFinished);

        if(m_animation != null) {
            m_animPlayer = new AnimPlayer(m_animation);
        } else {
            m_animation = gameObject.GetComponentInChildren<Animation>();
            m_animPlayer = new AnimPlayer(m_animation);
            PuppetLogWarning("对象动画组件未设置。");
        }
        if(m_prop == null) m_prop = this.GetComponent<PuppetProperty>();
        if(m_puppetAI == null) m_puppetAI = this.GetComponent<PuppetAI>();
        if(controller == null) controller = this.GetComponent<CharacterController>();
        if(m_puppetCollider == null) m_puppetCollider = this.GetComponent<CapsuleCollider>();
        if(m_puppetCollider != null) {
            m_objheight = m_puppetCollider.center.y + m_puppetCollider.height / 2;
            m_colliderRange = m_puppetCollider.radius;
        }
        m_colliders = this.GetComponentsInChildren<Collider>(false);
        Transform skillRootTF = objTF.Find("skills");
        if(skillRootTF != null) m_skillPackage = skillRootTF.GetComponent<SkillPackage>();
        m_posRootTF = objTF.Find("pos");
        m_bindObjsRootTF = objTF.Find("bindObjs");
        m_damagePos = GetPosTF("dmgpos");
        headPosTF = GetPosTF("top_1");
        if(m_bindObjsRootTF == null) {
            m_bindObjsRootTF = new GameObject("bindObjs").transform;
            m_bindObjsRootTF.parent = objTF;
        }
        m_visibleNodes = gameObject.GetComponentsInChildren<Renderer>();

        //Profiler.EndSample();
        //Profiler.BeginSample("Puppet.Init2");
        m_FSMSystem.RegistFSMState(new PuppetStandState(this, "Stand", (int)PuppetStateID.Stand));
        m_FSMSystem.RegistFSMState(new PuppetShowState(this, "Show", (int)PuppetStateID.Show));
        m_FSMSystem.RegistFSMState(new PuppetRunState(this, "Run", (int)PuppetStateID.Run));
        m_FSMSystem.RegistFSMState(new PuppetHurtState(this, "Hurt", (int)PuppetStateID.Hurt));
        m_FSMSystem.RegistFSMState(new PuppetClimbUpState(this, "ClimbUp", (int)PuppetStateID.ClimbUp));
        m_FSMSystem.RegistFSMState(new PuppetReloadState(this, "Reload", (int)PuppetStateID.Reload));
        m_FSMSystem.RegistFSMState(new PuppetDeathState(this, "Death", (int)PuppetStateID.Death));
        m_FSMSystem.RegistFSMState(new PuppetSkillState(this, "Skill", (int)PuppetStateID.Skill));
        m_FSMSystem.RegistFSMState(new PuppetWinState(this, "Win", (int)PuppetStateID.Win));
        m_FSMSystem.RegistFSMState(new PuppetControlState(this, "Control", (int)PuppetStateID.Control));

        initAnim();
        ClearSkillMove();
        ResetObj();
        _setState(PuppetStateID.Stand);
        //Profiler.EndSample();
    }

    //人物初始化后会站着不动，需要调用ActiveObj才会启动。
    public void ActiveObj() {
#if UNITY_EDITOR
        if(debug_isInitWithServerData == false) {
            PuppetLogError("没有初始化服务器数据.");
        }
#endif
        m_isActived = true;
        if(m_puppetAI != null) {
            m_puppetAI.StartFight();
        }
    }

    //重置复用属性。重用人物前需要调用。
    public void ResetObj() {
        m_isActived = false;
        debug_isInitWithServerData = false;
        m_FSMSystem.StartStateMachine();
        CurHp = MaxHp;
        CurAnger = 0;
        Invisable = true;
        objGID = "";
        m_buffContainer.Clear();
        EnableColliders(true);
        _setState(PuppetStateID.Stand);
    }


    void initAnim() {
        //为轻受伤设置新的用于融合的动画片段
        if(MixBoneTF_lightHurt != null) {
            Animation anim = m_animPlayer.m_anim;
            mixLightHurtFAnimName = lightHurtBackwardAnimName + "_mix";
            anim.AddClip(m_animPlayer.GetAnimation(lightHurtBackwardAnimName).clip, mixLightHurtFAnimName);
            AnimationState newMixHurt = m_animPlayer.GetAnimation(mixLightHurtFAnimName);
            newMixHurt.blendMode = AnimationBlendMode.Additive;
            newMixHurt.AddMixingTransform(MixBoneTF_lightHurt);
            isMixBone = true;
        }

        m_animPlayer.SetupAnim(attackStandAnimName,         0, 1.0f, WrapMode.Loop);
        m_animPlayer.SetupAnim(standAnimName,               0, 1.0f, WrapMode.Loop);
        m_animPlayer.SetupAnim(showAnimName,                0, 1.0f, WrapMode.Loop);
        m_animPlayer.SetupAnim(runAnimName,                 0, 1.0f, WrapMode.Loop);
        m_animPlayer.SetupAnim(winAnimName,                 0, 1.0f, WrapMode.Loop);
        m_animPlayer.SetupAnim(deadAnimName,                0, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(reloadAnimName,              0, 1.0f, WrapMode.ClampForever);
        //受伤及其融合动画
        m_animPlayer.SetupAnim(lightHurtForwardAnimName,    1, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(lightHurtBackwardAnimName,   1, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(heavyHurtForwardAnimName,    1, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(heavyHurtBackwardAnimName,   1, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(knowDownForwardAnimName,     1, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(knowDownBackwardAnimName,    1, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(climbUpForwardAnimName,      1, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(climbUpBackwardAnimName,     1, 1.0f, WrapMode.ClampForever);
        m_animPlayer.SetupAnim(mixLightHurtFAnimName,       1, 1.0f, WrapMode.ClampForever);

    }
    #endregion

    // Update is called once per frame
    void Update() {
        float dt = Time.deltaTime;

        if(t_curGCD > 0) { t_curGCD -= dt; }
        if(m_onGuardTime > 0) {
            m_onGuardTime -= dt;
        }
        updateDir();
    }
    void updateDir() {
        Vector3 targetDir = TargetLookingDir;
        //如果面向来回小角度摆动，则继续以之前面向

        if(targetDir.IsZero2D() == false && false == Tools.Vector3Equals2D(objTF.forward, targetDir)) {
            float rotationSpeed = LookingRotationSpeed;
            if(StateID != PuppetStateID.Run) {
                rotationSpeed *= 2;
            }
            objTF.rotation = Quaternion.RotateTowards(objTF.rotation, m_targetLookingDirQ, rotationSpeed * Time.deltaTime);
        }

    }

    Vector3 lastFaceDir;
    Vector3 lastSwingDir;  //摆动方向

    /// <summary>
    /// 面向是否来回摆动
    /// </summary>
    /// <returns></returns>
    bool checkSwingFaceDir(Vector3 newDir) {
        bool result = false;
        if(lastFaceDir.IsZero2D()) {
            lastFaceDir = newDir;
            return false;
        }

        Vector3 swingDir = lastFaceDir - newDir;
        if(lastSwingDir.IsZero2D()) {
            lastSwingDir = swingDir;
            return false;
        }

        //a*b = |a||b|cosA , cosA < 0 是钝角
        if(Vector3.Dot(swingDir, lastSwingDir) < 0) {
            Debug.LogFormat("SwingFaceDir! FaceDir[{0}]->[{1}]", lastFaceDir, newDir);
            lastFaceDir = Vector3.zero;
            lastSwingDir = Vector3.zero;
            result = true;
        } else {
            lastFaceDir = objTF.forward;
            lastSwingDir = swingDir;
        }

        return result;
    }

    void OnEnable() {
        Invisable = true;
    }

    void OnDisable() {
        Invisable = false;
    }

    /// <summary>
    /// 不可见。只会隐藏指定节点。比如meshRender的节点。
    /// </summary>
    public bool Invisable {
        get { return m_invisible; }
        set {
            m_invisible = value;
            for(int i = 0; i < m_visibleNodes.Length; i++) {
                m_visibleNodes[i].SetActive(m_invisible);
            }
        }
    }

    public void EnableColliders(bool b) {
        if(m_colliders != null) {
            for(int i = 0; i < m_colliders.Length; i++) {
                m_colliders[i].enabled = b;
            }
        }
    }

    #region Is/Set/Get接口
    //会计算Buff影响
    public int GetPropWithBuff(PuppetIntPropID propID) {
        int propValue = m_prop.GetIntProp(propID);
        return propValue + (int)m_buffContainer.GetPropChangeValue((int)propID, propValue);
    }

    public float GetPropWithBuff(PuppetFloatPropID propID) {
        float propValue = m_prop.GetFloatProp(propID);
        return propValue + m_buffContainer.GetPropChangeValue((int)propID + BUFF_FLOAT_PROP_BEGIN, propValue);
    }
    //未受Buff影响的原始属性
    public int GetRawProp(PuppetIntPropID propID) {
        return m_prop.GetIntProp(propID);
    }
    public float GetRawProp(PuppetFloatPropID propID) {
        return m_prop.GetFloatProp(propID);
    }
    public string GetRawProp(PuppetStrPropID propID) {
        return m_prop.GetStrProp(propID);
    }

    /// <summary>
    /// 获取人物身上绑定的坐标。根节点Pos下面保存的坐标。注意如果设置了relationNode脚本，得到的是绑定的节点。
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="playPosAtObjPos"></param>
    /// <returns></returns>
    public Transform GetPosTF(string posName) {
        Transform posTF = null;
        if(string.IsNullOrEmpty(posName)) {
            posTF = BindObjsRootTF;
        } else {
            m_posTFCache.TryGetValue(posName, out posTF);
            if(posTF == null) {
                posTF = PosRootTF.Find(posName);
                if(posTF != null) {
                    RelationNode relate = posTF.GetComponent<RelationNode>();
                    if(relate != null && relate.BindTF != null) {
                        posTF = relate.BindTF;
                    }
                    m_posTFCache.Add(posName, posTF);
                }
            }
        }
        if(posTF == null) {
            posTF = BindObjsRootTF;
        }
        return posTF;
    }

    public bool IsMoving() {
        return m_moveInfo != null && m_moveInfo.isEnable;
    }

    public bool IsReloading() {
        return StateID == PuppetStateID.Reload;
    }

    virtual public bool IsCanAttack() {
        if(IsDead
                || StateID == PuppetStateID.Hurt
                || StateID == PuppetStateID.ClimbUp
                || StateID == PuppetStateID.Skill
                || StateID == PuppetStateID.Reload
                || StateID == PuppetStateID.Win) {
            return false;
        }
        return true;
    }

    //是否是战斗状态/和平状态。
    public bool IsOnGuardState() {
        return m_onGuardTime > 0;
    }

    //被攻击、攻击别人会进入战斗状态
    public void SetOnGuardState() {
        m_onGuardTime = MaxGuardTime;
    }

    public void ClearOnGuardState() {
        m_onGuardTime = 0;
    }

    public bool IsCastingSkill() {
        return StateID == PuppetStateID.Skill;
    }

    public bool IsReleaseLoopSkill() {
        return m_skillsystem.IsReleaseLoopSkill();
    }

    bool IsCanSkill() {
        if(StateID == PuppetStateID.Hurt || StateID == PuppetStateID.Death) {
            return false;
        }
        return true;
    }

    //弹匣都空了，没有任何子弹了，无法释放。
    public bool IsAmmoEmpty(int bulletID) {
        AmmoPouch ammoPouch = GetAmmoPouch(bulletID);
        if(ammoPouch.IsInfinitiBullet || ammoPouch.bulletCount > 0) {
            return false;
        } else {
            return true;
        }
    }

    public PuppetCampID CampID {
        get { return m_prop.myCampID; }
    }

    public ObjType ObjTypeID {
        set {
            m_objType = value;
            if(m_realObjTypeID == ObjType.None) {
                //只设置一次。
                m_realObjTypeID = ObjTypeID;
            }
            SetLayer(ObjectManager.Share().GetObjLayerID(m_objType));
            m_prop.myCampID = ObjectManager.Share().GetObjCampID(m_objType);
        }
        get { return m_objType; }
    }

    void SetLayer(LayerName layer) {
        int layerID = LayerMask.NameToLayer(layer.ToString());
        gameObject.layer = layerID;
        for(int i = 0; i < m_visibleNodes.Length; i++) {
            m_visibleNodes[i].gameObject.layer = layerID;
        }
    }

    void SetLayer(int layerID) {
        gameObject.layer = layerID;
        for(int i = 0; i < m_visibleNodes.Length; i++) {
            m_visibleNodes[i].gameObject.layer = layerID;
        }
    }

    //本地唯一ID。注意!要在加载服务器数据后才可使用。
    public string GetGID() {
        if(string.IsNullOrEmpty(objGID) == false) {
            return objGID;
        }
        if(DebugSetting.Self.Debug_LocalScene) {
            objGID = nameEn + "_0_" + SeatID + "#" + GlobalID.GetGID();
        } else {
            if(debug_isInitWithServerData) {
                objGID = nameEn + "_" + serverObjDataID + "_" + SeatID + "#" + GlobalID.GetGID();
            } else {
                PuppetLogError("没有加载服务器数据，就使用了GetGID()");
            }
        }
        return objGID;
    }

    public void SetObjCameraLayer(bool b) {
        if(b) {
            ObjTypeID = ObjType.SkillingPlayer;
            //SetLayer(LayerMask.NameToLayer(LayerName.HeroCamera.ToString()));
        } else {
            ObjTypeID = m_realObjTypeID;
            //SetLayer(ObjectManager.Share().GetObjLayerID(m_objType));
        }
    }

    List<GameObject> effects = new List<GameObject>();
    List<GameObject> pausedEffects = new List<GameObject>();

    //英雄身上创建的特效。目前是为了人物暂停时，一起暂停特效。
    public void AttachEffect(GameObject effect) {
        if(effect == null) return;

        //DebugUtil.LogErrorFormat("[Puppet] AttachEffect obj:[{0}]", effect.name);
        effects.Add(effect);
    }
    public void UnattachEffect(GameObject effect) {
        if(effect == null) return;

        //DebugUtil.LogErrorFormat("[Puppet] UnattachEffect obj:[{0}]", effect.name);
        effects.Remove(effect);
    }

    void PauseAttachEffect() {
        pausedEffects.Clear();
        for(int i = 0; i < effects.Count; i++) {
            GameObject obj = effects[i];
            if(obj.activeSelf) {
                //DebugUtil.LogErrorFormat("[Puppet] PauseAttachEffect obj:[{0}]", obj.name);
                obj.SetActive(false);
                pausedEffects.Add(obj);
            }
        }
    }

    void ResumeAttachEffect() {
        for(int i = 0; i < pausedEffects.Count; i++) {
            //DebugUtil.LogErrorFormat("[Puppet] ResumeAttachEffect obj:[{0}]", pausedEffects[i].name);
            pausedEffects[i].SetActive(true);
        }
    }

    #endregion

    LinkedList<Vector3> moveTrack = new LinkedList<Vector3>();
    int MaxTrackCount = 20;

    #region 状态切换系列
    //行走检查
    public void SimpleMove(Vector3 nextPos) {
        if(DebugSetting.Self.moveUsingCharacterController) {
            controller.Move(nextPos - objTF.position);
        } else {
            objTF.position = nextPos;
        }
        nextPos.y = 5f;
        moveTrack.AddLast(nextPos);
        if(moveTrack.Count > MaxTrackCount) {
            moveTrack.RemoveFirst();
        }
    }

    //目前只有Death状态需要注意，其他基本都是true。。。除了Skill->Skill:true,状态可以打断。
    //bool[B,A]  A（当前状态）->B（新状态），是否允许切换
    bool[,] stateChangeAllow = {
//A:    Stand,  Show,   Run,    Hurt,   ClimbUp,Reload, Death,  Skill,  Win,    Control
        {false, true,   true,   true,  true,    true,   false,  true,   true,   true    },  // B:Stand,
        {true,  false,  true,   true,  true,    true,   false,  true,   true,   true    },  // Show,
        {true,  true,   false,  true,  true,    true,   false,  true,   true,   true    },  // Run,
        {true,  true,   true,   false, true,    true,   false,  true,   true,   true    },  // Hurt,
        {true,  true,   true,   true,  false,   true,   false,  true,   true,   true    },  // ClimbUp,
        {true,  true,   true,   true,  true,    false,  false,  true,   true,   true    },  // Reload,
        {true,  true,   true,   true,  true,    true,   false,  true,   true,   true    },  // Death,
        {true,  true,   true,   true,  true,    true,   false,  true,   true,   true    },  // Skill,
        {true,  true,   true,   true,  true,    true,   false,  true,   false,  true    },  // Win,
        {true,  true,   true,   true,  true,    true,   false,  true,   true,   false   },  // Control,
    };


    bool IsChangeStateAllow(PuppetStateID newStateID) {
        bool isStateAllow = true;
        int curState = m_FSMSystem.CurrentState;
        if(isStateAllow && curState >= 0) {
            isStateAllow = stateChangeAllow[(int)newStateID, curState];
            if(isStateAllow) {
                isStateAllow &= m_FSMSystem.GetCurFSMState().IsCanChangeState((int)newStateID);
            }
        }

        if(isStateAllow == false) {
            DebugUtil.LogWarningFormat("[Puppet]State Change Not Allowed. [{0}]->[{1}] [{2}]", ((PuppetStateID)curState).ToString(), newStateID.ToString(), GetGID());
        }
        return isStateAllow;
    }

    void _setState(PuppetStateID newStateID) {
        PuppetLog("切换状态:[{0}]", newStateID.ToString());
        if(m_FSMSystem != null) m_FSMSystem.CurrentState = (int)newStateID;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="stateID"></param>
    /// <returns> 是否允许切换状态 </returns>
    public bool SetState(PuppetStateID newStateID) {
        if(IsChangeStateAllow(newStateID)) {
            _setState(newStateID);
            return true;
        }
        return false;
    }

    #endregion

    #region 移动/面向接口系列
    public void MoveToPosition(Vector3 pos) {
        if(StateID == PuppetStateID.Run || SetState(PuppetStateID.Run)) {
            m_moveInfo.Reset();
            m_moveInfo.moveID = MoveID.WalkOrRun;
            m_moveInfo.moveType = MoveType.MoveTargetPos;
            m_moveInfo.moveTargetPos = pos;
        }
    }

    public void MoveToDirection(Vector3 dir) {
        if(StateID == PuppetStateID.Run || SetState(PuppetStateID.Run)) {
            m_moveInfo.Reset();
            m_moveInfo.moveID = MoveID.WalkOrRun;
            m_moveInfo.moveType = MoveType.MoveDir;
            m_moveInfo.moveDir = dir;
        }
    }

    public void MoveFollowToObj(Transform followTF) {
        if(StateID == PuppetStateID.Run || SetState(PuppetStateID.Run)) {
            m_moveInfo.Reset();
            m_moveInfo.moveID = MoveID.WalkOrRun;
            m_moveInfo.moveType = MoveType.MoveFollowObj;
            m_moveInfo.moveFollowTF = followTF;
        }
    }

    public void AddForceMove(MoveInfo moveInfo) {
        string id = "";
        moveInfo.isEnable = true;
        if(moveInfo.moveID == MoveID.OtherForceMove) {
            id = moveInfo.moveID.ToString() + GlobalID.GetGID();
        } else {
            id = moveInfo.moveID.ToString();
        }
        m_forceMoveInfos.TryAdd<string, MoveInfo>(id, moveInfo);
    }

    public void SetSkillMove(MoveInfo moveInfo) {
        if(StateID != PuppetStateID.Skill) {
            return;
        }
        m_skillMoveInfo = moveInfo;
        m_skillMoveInfo.isEnable = true;
    }

    public void ClearSkillMove() {
        m_skillMoveInfo = null;
    }

    public void LookAtDir(Vector3 m_dir) {
        if(m_dir.IsZero2D()) {
            return;
        }
        m_dir.y = 0f;
        m_targetLookingDir = m_dir;
        m_targetLookingDirQ = Quaternion.LookRotation(m_dir);
    }
    public void LookAtDirImm(Vector3 m_dir) {
        m_targetLookingDir = Vector3.zero;
        m_targetLookingDirQ = Quaternion.identity;
        objTF.forward = m_dir;
    }

    public void LookAtPosition(Vector3 pos) {
        LookAtDir(pos - objTF.position);
    }
    public void LookAtPositionImm(Vector3 pos) {
        LookAtDirImm(pos - objTF.position);
    }

    #endregion

    #region BUFF
    public void AddBuff(int buffID, string casterGID, PuppetCampID casterCampID, int skillID, uint skillCastID) {
        //检查Buff目标类型
        BaseBuffData buffData = BuffManager.Share().GetBuffData(buffID);
        if(this.IsTargetFit(casterGID, casterCampID, buffData.targetType)) {
            m_buffContainer.AddBuff(buffID, casterGID, skillID, skillCastID);
//             SynInfoUploader.Share().UploadBuffChange(
//                 this.GetGID(),
//                 casterGID,
//                 buffID,
//                 buffData.m_duration
//             );
        }
    }
    #endregion

    #region 技能系列
    public PuppetSkillCircle GetSkillCircle() {
        if(m_skillCircle == null) {
            m_skillCircle = gameObject.AddComponentSafe<PuppetSkillCircle>();
        }
        return m_skillCircle;
    }

    //人物播放技能动画。
    public void playSkillAnim(SkillAnimInfo animInfo) {
        if(StateID != PuppetStateID.Skill) {
            PuppetLogError("playSkillAnim with Error State. skillInfo:[{0}]", animInfo.Dump());
            return;
        }
        if(SkillInfo == null) {
            SkillInfo = animInfo;
            NextSkillInfo = null;
        } else {
            NextSkillInfo = animInfo;
        }
        //SetState(PuppetStateID.Skill);
    }
    public SkillCheckResult CastSkill(int skillID) {
        SkillCheckResult castRet = SkillCheckResult.SkillRet_Fail_Unkown;

        if(m_isActived == false) { castRet = SkillCheckResult.SkillRet_Fail_ObjNotActived; }
        else if(IsTimeFreezing()) { castRet = SkillCheckResult.SkillRet_Fail_TimeFreezing; }
        else if(IsChangeStateAllow(PuppetStateID.Skill) == false) {
            castRet = SkillCheckResult.SkillRet_Fail_Busying;
        } else {
            castRet = m_skillsystem.CastSkill(skillID);
            if(castRet <= SkillCheckResult.SkillRet_RunningWell) {
                SetOnGuardState();
                _setState(PuppetStateID.Skill);
                t_curGCD = MaxGCD;
            }
        }

        if(castRet <= SkillCheckResult.SkillRet_RunningWell) {
            PuppetLog("Cast Skill Begin. Result:[{0}]", castRet.ToString());
        } else {
            PuppetLog("Cast Skill Fail. Result:[{0}]", castRet.ToString());
        }
        return castRet;
    }
    public SkillCheckResult CastSkill(SkillTL skill) {

        SkillCheckResult castRet = SkillCheckResult.SkillRet_Fail_Unkown;

        if(m_isActived == false) { castRet = SkillCheckResult.SkillRet_Fail_ObjNotActived; }
        else if(IsTimeFreezing()) { castRet = SkillCheckResult.SkillRet_Fail_TimeFreezing; }
        else if(IsChangeStateAllow(PuppetStateID.Skill)) {
            castRet = m_skillsystem.CastSkill(skill);
            if(castRet <= SkillCheckResult.SkillRet_RunningWell) {
                SetOnGuardState();
                _setState(PuppetStateID.Skill);
                t_curGCD = MaxGCD;
            }
        }

        if(castRet <= SkillCheckResult.SkillRet_RunningWell) {
            PuppetLog("Cast Skill Begin. Result:[{0}]", castRet.ToString());
        } else {
            PuppetLog("Cast Skill Fail. Result:[{0}]", castRet.ToString());
        }

        return castRet;
    }

    void OnSkillCastBegin(SkillTL skill) {
        CurAnger -= skill.m_skillData.angerConsume;
    }

    void OnSkillFinished(SkillTL skill) {
        if(skill == null) {
            return;
        }

        CurAnger += skill.m_skillData.angerAdd;
        //大招释放后的添加CD
        if(skill.m_skillData.m_skillType == SkillType.ActiveSkill) {
            t_curGCD = ActiveSkillPostCD;
        }
    }

    public void BreakLoopSkill() {
        PuppetLog("BreakLoopSkill");
        m_skillsystem.BreakLoopSkill();
    }

    public void StopSkill() {
        PuppetLog("StopSkill");
        NextSkillInfo = null;
        SkillInfo = null;
        GetSkillCircle().CancelSelectMode();
        m_skillsystem.StopSkill();
        SetState(PuppetStateID.Stand);
    }

    public bool IsCasting() {
        return m_skillsystem.IsCasting();
    }

    #endregion

    #region 回调接口

    public void RegistEvent_DeadRelease(PuppetEvent puppetEvent) {
        onDeadRelease -= puppetEvent;
        onDeadRelease += puppetEvent;
    }

    #endregion

    #region 人物动作接口

    //AI、状态机、动画、技能全部暂停。
    public void TimeFreezing() {
        if(m_isTimeFreezing) { return; }
        m_isTimeFreezing = true;
        m_puppetAI.Pause();
        m_animPlayer.Pause();
        m_skillsystem.Pause();
        m_FSMSystem.Pause();
        PauseAttachEffect();
    }

    public void ResumeTimeFreezing() {
        if(m_isTimeFreezing == false) { return; }
        m_isTimeFreezing = false;
        m_puppetAI.Resume();
        m_animPlayer.Resume();
        m_skillsystem.Resume();
        m_FSMSystem.Resume();
        ResumeAttachEffect();
    }

    public bool IsTimeFreezing() {
        return m_isTimeFreezing;
    }

    public void StopAction() {
        StopMove();
        StopSkill();
    }

    public void StopMove() {
        m_moveInfo.StopMove();
        if(StateID == PuppetStateID.Run) {
            SetState(PuppetStateID.Stand);
        }
    }

    public void Stand() {
        PuppetLog("Stand");
        m_moveInfo.StopMove();
        SetState(PuppetStateID.Stand);
    }
    public void Hurt() {
        PuppetLog("Hurt");
        SetOnGuardState();
        //策划说：受伤状态不能打断任何东西
//         if(curDamageInfo != null) {
//             if(curDamageInfo.hurtType != HurtType.NoHurtAnim
//                     && (m_skillsystem.CurSkill != null && m_skillsystem.CurSkill.SkillType != SkillType.ActiveSkill)) {
//                 if(m_skillsystem.TryInterrupt() == SkillCheckResult.SkillRet_OK) {
//                     SetState(PuppetStateID.Hurt);
//                 }
//             }
//         }
    }

    public void Reload(SkillTL gunSkill) {
        if(gunSkill != null && gunSkill.m_skillData.IsNeedReloadLikeAGun) {
            PuppetLog("Reload");
            if(SetState(PuppetStateID.Reload)) {
                curGunSkill = gunSkill;
            }
        }
    }

    public void Win() {
        SetState(PuppetStateID.Win);
    }

    public void DeactiveObj() {
        StopMove();
        StopSkill();
        if(m_puppetAI) m_puppetAI.StopFight();
        m_isActived = false;
    }

    public void Dead() {
        DeactiveObj();
        SetState(PuppetStateID.Death);
        //2. 隐藏碰撞框
        EnableColliders(false);
        CurHp = 0;
        CurAnger = 0;
        DebugUtil.LogFormat("[Puppet] Dead. [{0}]  [{1}]", name, CurHp);
        if(deadRemainsPrefab != null) {
            GameObject prefab = GameObjectLoader.Ins.GetPrefabObj(GameConstant.PrefabPath_Effect + deadRemainsPrefab) as GameObject;
            ObjectRecycler.Instance.InstantiatePrefab(prefab, Pos, Quaternion.identity);
            if(prefab && prefab.GetComponentSafe<ObjRecycleTimer>() == null) {
                DebugUtil.LogErrorFormat("策划注意：特效[{0}]应当添加ObjRecycleTimer脚本，用于标记特效何时删除。该特效是死亡残骸/特效", prefab);
            }
        }
    }

    //释放对象
    public void DeadRelease() {
        PuppetLog("AAAAAAA, I'm Die");

        //1. 隐藏，关闭模块功能
        Invisable = false;
        if(m_puppetAI != null)  m_puppetAI.StopFight();
        m_buffContainer.Clear();
        //2. 释放对象到缓存池
        //由ObjMgr处理释放。
        onDeadRelease(this);
    }
    #endregion

    #region 枪械系列
    public AmmoPouch GetAmmoPouch(int bulletID) {
        AmmoPouch ammo = null;
        bulletPackage.TryGetValue(bulletID, out ammo);
        return ammo;
    }

    public void FillCurGunSkill() {
        if(curGunSkill != null) {
            curGunSkill.FillBullet(GetAmmoPouch(curGunSkill.m_skillData.bulletID));
            curGunSkill = null;
        }
    }
    #endregion

    #region 获取动画
    public string GetStandAnim() {
        if(IsOnGuardState() && string.IsNullOrEmpty(attackStandAnimName) == false) {
            return attackStandAnimName;
        } else {
            return standAnimName;
        }
    }

    public string GetHurtAnim() {
        if(curDamageInfo == null) return "";
        string CurHurtAnimName = "";
        switch(curDamageInfo.hurtType) {
            case HurtType.LightHurt:
                CurHurtAnimName =
                    curDamageInfo.isHurtForward ?
                    (string.IsNullOrEmpty(mixLightHurtFAnimName) == false ? mixLightHurtFAnimName : lightHurtForwardAnimName) :
                    lightHurtBackwardAnimName;
                break;
            case HurtType.HeavyHurt:
                CurHurtAnimName = curDamageInfo.isHurtForward ? heavyHurtForwardAnimName : heavyHurtBackwardAnimName;
                break;
            case HurtType.KnockDown:
                CurHurtAnimName = curDamageInfo.isHurtForward ? knowDownForwardAnimName : knowDownBackwardAnimName;
                break;
        }
        return CurHurtAnimName;
    }

    //以玩家英雄视角。目前用于FPS镜头隐藏队友特效。
    public bool IsHeroOrFriend() {
        return m_objType == ObjType.PlayerSelf || m_objType == ObjType.FriendPlayer || m_objType == ObjType.FriendNPC || m_objType == ObjType.SkillingPlayer;
    }

    //目前用于添加怪物技能的根据HP触发可释放次数。
    public bool IsMonster() {
        return m_objType == ObjType.Monster || m_objType == ObjType.Boss;
    }

    /// <summary>
    /// 对象产生的特效的LayerID。
    /// 英雄产生的特效是HeroEffect。用于FPS时隐藏队友的特效。
    /// </summary>
    /// <returns></returns>
    public int GetEffectLayerID() {
        LayerName layerName = LayerName.Default;
        if(IsHeroOrFriend()) {
            layerName = LayerName.HeroEffect;
        }
        return LayerMask.NameToLayer(layerName.ToString());
    }

    public HurtType GetHurtType() {
        return curDamageInfo.hurtType;
    }

    public string GetClimbUpAnim() {
        if(curDamageInfo.hurtType != HurtType.KnockDown) {
            return "";
        }
        return curDamageInfo.isHurtForward ? climbUpForwardAnimName : climbUpBackwardAnimName;
    }

    #endregion

    #region 战斗
    /// <summary>
    /// 对于obj，targetObj是否符合TargetType。
    ///
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="targetObj"></param>
    /// <param name="targetType"></param>
    /// <returns></returns>
    public bool IsTargetFit(string targetGID, PuppetCampID targetCampID, TargetTypeID buffTargetTypeMask) {
        TargetSelectType targetSelectType;
        if(buffTargetTypeMask.IsNothing()) {
            return true;
        } else if(GetGID() == targetGID) {
            targetSelectType = TargetSelectType.Self;
        } else {
            CampRelation camp = ObjectManager.Share().GetCampRelation(this.CampID, targetCampID);
            targetSelectType = ObjectManager.CampRelation2SelectType(camp);
        }

        if(buffTargetTypeMask.CheckMaskWithID((int)targetSelectType)) {
            return true;
        }

        return false;
    }

    public ControlInfo m_controlInfo;

    public void ApplyControlState(ControlInfo info) {
        if(info == null || info.m_controlState == ControlState.None) {
            return;
        }
        m_controlInfo = info;

        switch(info.m_controlState) {
            case ControlState.Stun: {
                    SetState(PuppetStateID.Control);
                }
                break;
            case ControlState.Sheep: {
                    SetState(PuppetStateID.Control);
                }
                break;
        }
    }

    /// <summary>
    /// 受伤的统一接口
    ///
    /// 没有限制非激活玩家的受伤。因为英雄可能会一边走向下一场，一边受到加血buff影响。
    /// </summary>
    /// <param name="info"></param>
    public void ApplyDamage(DamageInfo info) {
        if(info.receiverGID != GetGID()) {
            PuppetLogError("DamageInfo的受伤者不对应！？ DmgInfo:receiver[{0}] obj[{1}]", info.receiverGID, GetGID());
        }

        int damage = info.damage;
        if(info.damageType == DamageType.Damage) {
            if(IsDead == false) {
                //计算护盾
                float newDamage = (int)m_buffContainer.ApplyReceiveDamage((float)damage);
                PuppetLog("Damage [{0}]=>[{1}] damage:[{2}]", info.attackerGID, GetGID(), damage);
                damage = (int)newDamage;
                if(newDamage > 0 && damage == 0) {
                    damage = 1;
                }
                if(damage > 0) {
                    //计算怒气
                    if(info.isCanAddAnger) {
                        CurAnger += GetPropWithBuff(PuppetIntPropID.Prop_anger);
                    }

                    //buff的数值在buff触发时计算总数值。
                    if(info.dmgSource != DamageSource.Buff) DamageRecount.Share().AddDamage(info.skillCastID, damage);
                    CurHp -= damage;
                    //BattleUIHelper.Share().ShowHurtEffect(HURTNUMTYPE.NORMALHURTNUM, ShowDamagePos, damage);

                }
            }
        } else if(info.damageType == DamageType.Healing) {
            if(damage > 0 && IsDead == false) {
                if(info.dmgSource != DamageSource.Buff) DamageRecount.Share().AddHealth(info.skillCastID, damage);
                CurHp += damage;
                //BattleUIHelper.Share().ShowHurtEffect(HURTNUMTYPE.RECOVERLIFENUM, ShowDamagePos, damage);
            }
        }


        if(damage > 0 && IsDead == false) {
            //HP变化
//             SynInfoUploader.Share().UploadHpChange(
//                 GetGID(),
//                 CurHp,
//                 MaxHp,
//                 info.damageType == DamageType.Damage ? -damage : damage,
//                 (int)info.dmgSource,
//                 info.dmgSource == DamageSource.Skill ? info.skillID : info.buffID,
//                 info.attackerGID,
//                 info.buffLastTime);
        }

        curDamageInfo = info;

        if(IsDead) {
            Dead();
        } else {
            Hurt();
            //处理Buff
            for(int i = 0; i < info.buffIDs.Count; i++) {
                AddBuff(info.buffIDs[i], info.attackerGID, info.attackerCampID, info.skillID, info.skillCastID);
            }
        }
    }

    void UploadInfoToServer(DamageInfo info) {

    }

    public void Guide_FullAnger() {
        CurAnger = MaxAnger;
    }

    #endregion

    #region LOG方法
    public void PuppetLog(string msgformat, params object[] args) {
        if(PuppetLogFlag == false) {
            return;
        }
        DebugUtil.LogFormat("[Puppet]obj:[{0}]state:[{1}][{2}] {3} ",
                            string.IsNullOrEmpty(objGID) ? nameEn : GetGID(),
                            StateID.ToString(),
                            m_skillsystem.CurSkill != null ? m_skillsystem.CurSkill.DumpSkill() : "NoSkill",
                            string.Format(msgformat, args));
    }
    public void PuppetLogWarning(string msgformat, params object[] args) {
        if(PuppetLogFlag == false) {
            return;
        }
        DebugUtil.LogWarningFormat("[Puppet]obj:[{0}]state:[{1}][{2}] {3} ",
                                   string.IsNullOrEmpty(objGID) ? nameEn : GetGID(),
                                   StateID.ToString(),
                                   m_skillsystem.CurSkill != null ? m_skillsystem.CurSkill.DumpSkill() : "null",
                                   string.Format(msgformat, args));
    }
    public void PuppetLogError(string msgformat, params object[] args) {
        DebugUtil.LogErrorFormat("[Puppet]obj:[{0}]state:[{1}][{2}] {3} ",
                                 string.IsNullOrEmpty(objGID) ? nameEn : GetGID(),
                                 StateID.ToString(),
                                 m_skillsystem.CurSkill != null ? m_skillsystem.CurSkill.DumpSkill() : "null",
                                 string.Format(msgformat, args));
    }

    void OnDrawGizmos() {
        if(Application.isPlaying && DamageReceiverCollider.IsDrawColliderWire == false) {
            return;
        }
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(transform.position, moveColliderRange);

        if(moveTrack.Count > 0) {
            Vector3 lastPos = moveTrack.First.Value;
            foreach(Vector3 pos in moveTrack) {
                Gizmos.DrawSphere(pos, 0.03f);
                Gizmos.DrawLine(lastPos, pos);
                lastPos = pos;
            }
        }
    }

    #endregion

}
}